package uk.ac.cam.juliet.zedcat.socialnetworking;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.SQLException;

import javax.swing.*;
import java.awt.*;

/**
 *  The graphical user interface to the database analysis.
 *  @author Daniel Wright
 */

public class SwingGUIFrame extends JFrame {
	
	private static final long serialVersionUID = -5547718339247752342L;

	// Database Controller.
	private DatabaseController dbc;
	
	// Buttons.
	private JButton bMakeConnection;
	private JButton bPoll;
	private JButton bAutoPoll;
	private JButton bRefreshCreds;
	private JButton bTestMessage;
	private JButton bDisConn;
	
	// Settings.
	private JTextField tAddress;
	private JTextField tUsername;
	private JPasswordField tPassword;
	//Status.
	private JTextArea tStatus;
	// Statistics.
	private JTextArea tPollCount;
	private JTextArea tTimestamp;
	private JTextArea tMessageCount;
	private JTextArea tNumberOfSightingsProcessed;
	// Most recent.
	private JTextArea tMostRecentUpdate;
	
	// Autopolling thread.
	private AutoPollThread autopoll;
	private boolean autoPollingState;
	
	private Logger lg;
	private int autopolltime = 10000;

	public SwingGUIFrame() {
		// Frame construction stuff.
		setTitle("Team Juliet - ZedCat Social Media Controller");
		this.setLayout(new BorderLayout());
		this.setPreferredSize(new Dimension(750,500));
		this.setResizable(false);
		
		Container framePane = this.getContentPane();
		
		// Buttons Panel
		JPanel pButtons = new JPanel();
		pButtons.setLayout(new GridLayout(1,0));
		pButtons.setPreferredSize(new Dimension(750,25));
		
		
		bMakeConnection = new DbConnButton();
		pButtons.add(bMakeConnection);
		
		bDisConn = new DisconnectButton();
		pButtons.add(bDisConn);
		
		bPoll = new PollButton();
		pButtons.add(bPoll);

		bAutoPoll = new AutoPollButton();
		pButtons.add(bAutoPoll);
		
		bRefreshCreds = new RefreshCredsButton();
		pButtons.add(bRefreshCreds);
		
		bTestMessage = new TestMessageButton();
		pButtons.add(bTestMessage);
		
		setButtonsClickable(false);
		
		// Settings Panel
		JPanel pSettings = new JPanel();
		pSettings.setLayout(null);
		pSettings.setPreferredSize(new Dimension(200,0));
		pSettings.setBackground(Color.black);
		
		JLabel lAddress = new JLabel("Database Address:");
		lAddress.setForeground(Color.orange);
		lAddress.setBounds(10, 0,180, 20);
		pSettings.add(lAddress);
		
		tAddress = new JTextField("//localhost:3306/juliet");
		tAddress.setForeground(Color.white);
		tAddress.setBackground(Color.black);
		tAddress.setBounds(10,20,180,20);
		tAddress.setBorder(BorderFactory.createLineBorder(Color.ORANGE));
		tAddress.setCaretColor(Color.WHITE);
		pSettings.add(tAddress);
		
		JLabel lUsername = new JLabel("Username:");
		lUsername.setBounds(10, 50,180, 20);
		lUsername.setForeground(Color.orange);
		pSettings.add(lUsername);
		
		tUsername = new JTextField("");
		tUsername.setBounds(10,70,180,20);
		tUsername.setForeground(Color.white);
		tUsername.setBackground(Color.black);
		tUsername.setBorder(BorderFactory.createLineBorder(Color.ORANGE));
		tUsername.setCaretColor(Color.WHITE);
		pSettings.add(tUsername);
		
		JLabel lPassword = new JLabel("Password:");		
		lPassword.setBounds(10, 100,180, 20);
		lPassword.setForeground(Color.orange);
		pSettings.add(lPassword);
		
		tPassword = new JPasswordField("");
		tPassword.setForeground(Color.white);
		tPassword.setBackground(Color.black);
		tPassword.setBounds(10, 120,180, 20);
		tPassword.setBorder(BorderFactory.createLineBorder(Color.ORANGE));
		tPassword.setCaretColor(Color.WHITE);
		pSettings.add(tPassword);
		
		// Statistics Panel
		JPanel pStatistics = new JPanel();
		pStatistics.setLayout(null);
		pStatistics.setPreferredSize(new Dimension(200,0));
		pStatistics.setBackground(Color.black);
		
		JLabel lNumOfPol = new JLabel("Number of polls:");
		lNumOfPol.setBounds(10,0,180,20);
		lNumOfPol.setForeground(Color.orange);
		pStatistics.add(lNumOfPol);
		
		tPollCount = new JTextArea("0");
		tPollCount.setForeground(Color.white);
		tPollCount.setBackground(Color.black);
		tPollCount.setEditable(false);
		tPollCount.setBounds(10, 20, 180, 20);
		pStatistics.add(tPollCount);
		
		JLabel lTime = new JLabel("Last sighting timestamp:");
		lTime.setBounds(10, 50, 180, 20);
		lTime.setForeground(Color.orange);
		pStatistics.add(lTime);
		
		tTimestamp = new JTextArea("Unknown");
		tTimestamp.setForeground(Color.white);
		tTimestamp.setBackground(Color.black);
		tTimestamp.setEditable(false);
		tTimestamp.setBounds(10, 70, 180, 20);
		pStatistics.add(tTimestamp);
		
		JLabel lUpdNum = new JLabel("Number of updates:");
		lUpdNum.setBounds(10,100,180,20);
		lUpdNum.setForeground(Color.orange);
		pStatistics.add(lUpdNum);
		
		tMessageCount = new JTextArea("0");
		tMessageCount.setForeground(Color.white);
		tMessageCount.setBackground(Color.black);
		tMessageCount.setEditable(false);
		tMessageCount.setBounds(10,120,180,20);
		pStatistics.add(tMessageCount);
		
		JLabel lSigNum = new JLabel("Number of proc sights:");
		lSigNum.setBounds(10, 150, 180, 20);
		lSigNum.setForeground(Color.orange);
		pStatistics.add(lSigNum);
		
		tNumberOfSightingsProcessed = new JTextArea("0");
		tNumberOfSightingsProcessed.setForeground(Color.white);
		tNumberOfSightingsProcessed.setBackground(Color.black);
		tNumberOfSightingsProcessed.setEditable(false);
		tNumberOfSightingsProcessed.setBounds(10,170,180,20);
		pStatistics.add(tNumberOfSightingsProcessed);	    
	    
		// Most recent update panel
		JPanel pMostRecentUpdate = new JPanel();
		pMostRecentUpdate.setLayout(null);
		pMostRecentUpdate.setPreferredSize(new Dimension(0,20));
		pMostRecentUpdate.setBackground(new Color(200,200,255));
		
		JTextArea lMostRecent = new JTextArea("    Most recent status update:");
		lMostRecent.setBounds(0, 0, 200, 20);
		lMostRecent.setFont(new Font("Arial",Font.PLAIN,15));
		lMostRecent.setEditable(false);
		lMostRecent.setFocusable(false);
		lMostRecent.setForeground(new Color(0,255,0));
		lMostRecent.setBackground(Color.BLACK);
		pMostRecentUpdate.add(lMostRecent);
		
		tMostRecentUpdate = new JTextArea("");
		tMostRecentUpdate.setFont(new Font("Arial",Font.PLAIN,15));
		tMostRecentUpdate.setForeground(new Color(0,255,0));
		tMostRecentUpdate.setBackground(Color.BLACK);
		tMostRecentUpdate.setBounds(200,0,550,20);
		pMostRecentUpdate.add(tMostRecentUpdate);
		
		// Status Panel
		
		tStatus = new JTextArea("Log:");
		tStatus.setLineWrap(true);
		tStatus.setEditable(false);
		tStatus.setBackground(Color.BLACK);
		tStatus.setForeground(Color.CYAN);
		
		JScrollPane ptStatus = new JScrollPane(tStatus, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		ptStatus.setBorder(BorderFactory.createLineBorder(Color.CYAN));
		// Add to content pane.
		framePane.add(pMostRecentUpdate, BorderLayout.NORTH);
		framePane.add(pSettings, BorderLayout.WEST);
		framePane.add(ptStatus, BorderLayout.CENTER);
		framePane.add(pStatistics, BorderLayout.EAST);
		framePane.add(pButtons, BorderLayout.SOUTH);
		
		// Link the Logger.
		lg = new Logger(tStatus, tPollCount,tTimestamp,tMostRecentUpdate,tMessageCount,tNumberOfSightingsProcessed);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		pack();
	}
	
	class DbConnButton extends JButton implements ActionListener {

		/**
		 * The button which makes an initial database connection.
		 * 
		 * @author Daniel Wright
		 */
		
		private static final long serialVersionUID = 7365435683553383163L;

		public DbConnButton() {
			super.setText("Connect");
			addActionListener(this);
		}

		public void actionPerformed(ActionEvent e) {
			if(dbc == null) {
				lg.log("Connecting to database");
				try {
					char[] psword = tPassword.getPassword();
					dbc = new DatabaseController(tAddress.getText(),tUsername.getText(),String.copyValueOf(psword), lg);
					for(int i = 0; i < psword.length;i++){
						psword[i] = 0;
					}
					dbc.connect();
					dbc.disconnect();
					setCredentialEntry(false,Color.GREEN);
					lg.log("Connected OK");
					lg.log("Polling for settings");
					dbc.pollForSettings();
					lg.log("Poll ok!");
					setButtonsClickable(true);
					bMakeConnection.setEnabled(false);
					
				} catch (ClassNotFoundException e1) {
					lg.log("Error: mysql-connector-java .jar file missing");
				} catch (SQLException e1) {
					if(e1.getMessage().startsWith("Access denied")) {
						lg.log("Error: Incorrect username/password");
						try {dbc.disconnect();} catch (SQLException e2) {}
						dbc = null;
						setCredentialEntry(true, Color.RED);
						return;
					}
					dbFailureHandler();
				}
			}
		}
	}
	
	class PollButton extends JButton implements ActionListener {
		/**
		 * A button which when pressed causes the database controller to poll.
		 */
		private static final long serialVersionUID = 2267740071361042475L;

		public PollButton() {
			super.setText("Poll");
			addActionListener(this);
		}

		public void actionPerformed(ActionEvent e) {
			try {
				dbc.poll();
				lg.increasePollCount();
			} catch (SQLException e1) {
				dbFailureHandler();
			}
		}
	}
	
	class AutoPollButton extends JButton implements ActionListener {

		private static final long serialVersionUID = 5080729511111456965L;

		public  AutoPollButton() {
			super.setText("Autopoll off");
			this.setBackground(new Color(255,0,0));
			addActionListener(this);
		}
		public void actionPerformed(ActionEvent e) {
			if (autoPollingState) {
				// Kill the polling thread.
				stopAutopoll();
				if(!autoPollingState){
					this.setText("Autopoll off");
					this.setBackground(new Color(255,0,0));	
				}	
			} else {
				// If the thread has never been run.
				if(autopoll == null) {
					startAutopoll(autopolltime);
					if(autoPollingState) {
						this.setText("Autopoll on");
						this.setBackground(new Color(0,255,0));
					}
				} else {
					// If the thread has been run.
					if (autopoll.isAlive()) {
						// Still running.
						lg.log("Unable to start thread.");
					} else {
						startAutopoll(autopolltime);
						if(autoPollingState) {
							this.setText("Autopoll on");
							this.setBackground(new Color(0,255,0));
						}
					}
				}
				
				
				
			}
		}
	}
	
	class RefreshCredsButton extends JButton implements ActionListener {

		/**
		 * A JButton which downloads the account credentials from the database.
		 */
		private static final long serialVersionUID = -5710907034113483464L;

		public RefreshCredsButton() {
			super.setText("Refresh Creds");
			addActionListener(this);
		}

		public void actionPerformed(ActionEvent e) {
			try {
				lg.log("Attempting to refresh credentials");
				dbc.refreshCredentials();
			} catch (SQLException e1) {
				System.err.println("Could not update credentials");
				e1.printStackTrace();
			}
		}
	}
	class TestMessageButton extends JButton implements ActionListener {
		/**
		 * A JButton which when pressed sends a test message to each of the registered accounts.
		 */
		private static final long serialVersionUID = -5409214689634337363L;
		public TestMessageButton() {super.setText("Test Message");addActionListener(this);}
		public void actionPerformed(ActionEvent e) {dbc.sendTestMessage();}
	}
	
	class DisconnectButton extends JButton implements ActionListener{
		/**
		 * A JButton which disconnects.
		 */
		private static final long serialVersionUID = 7884516139654957559L;
		public DisconnectButton() {super.setText("Disconnect");addActionListener(this);}
		public void actionPerformed(ActionEvent e) {dbFailureHandler();}
	}
	
	public class AutoPollThread extends Thread {
		private int time;
		
		public void setTime(int time) {
			this.time = time;
		}
		
		public void run() {
			while (autoPollingState) {
				try {
					dbc.poll();
					lg.increasePollCount();
				} catch (SQLException e1) {
					dbFailureHandler();
				}
				try {
					Thread.sleep(time);
				} catch (InterruptedException e) {}
			}
			lg.log("Autopolling disabled.");
		}
	}
	
	private void startAutopoll(int time) {
		autopoll = new AutoPollThread();
		autopoll.setTime(time);
		autoPollingState = true;
		autopoll.start();
		lg.log("Autopolling enabled");
	}
	
	private void stopAutopoll() {
		autoPollingState = false;
	}
	
	private void dbFailureHandler() {
		lg.log("Error: Database Connection Failed.");
		if(autoPollingState){
			lg.log("Attempting to stop autopolling...");
			stopAutopoll();
			bAutoPoll.setBackground(Color.red);
			bAutoPoll.setText("Autopoll off");
		}
		
		try {dbc.disconnect();} catch (SQLException e) {}
		dbc = null;
		setCredentialEntry(true,Color.white);
		setButtonsClickable(false);
		bMakeConnection.setEnabled(true);
	}
	
	private void setCredentialEntry(boolean f,Color c) {
		tUsername.setEnabled(f);
		tUsername.setForeground(c);
		tPassword.setEnabled(f);
		tPassword.setForeground(c);
		tAddress.setEnabled(f);
		tAddress.setForeground(c);
	}
	
	private void setButtonsClickable(boolean f) {
		bAutoPoll.setEnabled(f);
		bPoll.setEnabled(f);
		bRefreshCreds.setEnabled(f);
		bDisConn.setEnabled(f);
	}
	
}
